 /***ModuleWatcher By GYLite 2022-12-26
 * 模块观察类，监测模块运行的每个阶段以及加载模块引用的公共库
*/
class ModuleWatcher {		
	public static libRelease:boolean = true;		
	private _callBack: Function;
	private _thisObject: any;
	private _param: any;
	private _depends: Array<any>;	
	private _dependCounts: number;
	/**进入模块时间*/public startTime: number;
	/**离开模块时间*/public endTime: number;
	protected _uiData: UICtrlData;
	private _libList:string[];	
	private _haveEui:boolean;
	private _haveFairygui:boolean;
	private _dependLoadProgCall:Function;
	private _dependLoadProgObj:any;
	private _loadStartTime:number;
	public constructor(uiData: UICtrlData = null) {
		let s = this;
		s._dependCounts = NaN;
		s._uiData = uiData;
		s._libList = [];		
	}
	public setProg(func:Function, thisObj:any):void
	{
		this._dependLoadProgCall = func;
		this._dependLoadProgObj = thisObj;
	}
	public cancelDependLoad(): void {
		let s = this;
		if (s._depends && s._depends.length > 0) {
			let len: number;
			len = s._depends.length;
			while (--len > -1)
				Main.instance.myLoader.cancelLoadData(URLConf.moduleLibs + s._depends[len] + URLConf.getLibVer(), s.dependLoadComp, s);
			s._depends = null;
		}
	}
	private getUrl(uiPath: string, libDirVer: any = null): string[] {
		let s = this;
		let loadPath: any;
		let url = [];
		let uiLibDirVer:string;
		//加入版本号		
		if (libDirVer == "" || libDirVer == null) {
			libDirVer = UserData.getInstance().getQueryVariable("libDirVer");
			if(libDirVer == null)
			{
				uiLibDirVer = GameManager.getInstance().getLibDirVer(uiPath);
				libDirVer = uiLibDirVer == null?"":uiPath + "V/" + uiLibDirVer;
			}						
		}
		let libDirVerStr:string = libDirVer == "" ? libDirVer : libDirVer + "/";		
		loadPath = URLConf.moduleLibs + libDirVerStr + uiPath.replace(/\./g, "/");
		url.push(loadPath,libDirVer);
		return url;
	}
	/**模块开始，初始化启动之前，预处理依赖库
	 * @param func 主框架处理完成后的回调
	 * @param thisObj 回调的指向
	 * @param depends 当前允许加入depends参数，加载模块使用的依赖库,[依赖库js文件名称,依赖库js文件名称,依赖库js文件名称]
	 * @param param 模块传入的附加参数
	*/
	public modulePreStart(func: Function = null, thisObj: any = null, depends: Array<any> = null, param: any = null): void {
		let s = this;
		let path: string;
		let flag: boolean;
		let libName:string,libVer:string;
		let tempUrlArr:string[];
		let arr:any[];
		s._callBack = func;
		s._thisObject = thisObj;
		s._param = param;
		s._depends = depends;
		s._dependCounts = 0;
		if (s._depends && s._depends.length > 0) {
			let i: number, len: number;
			len = s._depends.length;
			for (i = 0; i < len; ) {
				libVer = URLConf.getLibVer();
				tempUrlArr = s.getUrl(s._depends[i]);
				arr = tempUrlArr[0].split("/");
				libName = arr[arr.length - 1];
				if(libName == "eui")
					s._haveEui = true;
				else if(libName == "fairygui")
					s._haveFairygui = true;
				path = tempUrlArr[0] + libVer;				
				if (GYLite.GYLoader.getDataResByKey(libName, true).length > 0)
				{
					Log.writeLog("公共库已存在!" + s._depends[i], Log.WARN);
					s._depends.splice(i,1);
					--len;					
					continue;
				}					
				++s._dependCounts;
				s._libList.push(path);				
				flag = true;
				++i;
			}			
			if (flag)
			{
				s._loadStartTime = Date.now();
				s.loadNextLib();
				return;
			}
			s.resUncompressComp();
		}
		else
			s.preStartOn();
	}
	private loadNextLib():boolean
	{let s = this;
		let url:string;
		if(s._libList.length > 0)
		{
			url = s._libList.shift()+ GameManager.getInstance().configMgr.libMD5();	
			GameManager.getInstance().loadData(url, s.dependLoadComp, s, s.dependLoadProg, GYLite.GYLoader.TYPE_BINARY, HTTPConf.M_GET,null,{save:false},UIControl.FAIL_RELOAD_COUNT);
			return true;
		}
		return false;			
	}
	private preStartOn(): void {
		let s = this;
		Log.writeLog(MultiLang.str17 + "-" + s._uiData.uiID, Log.IMPORTANT);
		if (s._callBack != null) {
			s._callBack.call(s._thisObject);
		}
	}
	/**模块开始，初始化之后启动之前
	 * @param func 主框架处理完成后的回调
	 * @param thisObj 回调的指向
	 * @param param 模块传入的附加参数
	*/
	public moduleStart(func: Function = null, thisObj: any = null, param: any = null): void {
		let s = this;
		s._callBack = func;
		s._thisObject = thisObj;
		//Bury.getInstance().startTime_2011 = s.startTime = GYLite.CommonUtil.loopTime;
		Log.writeLog(MultiLang.str18 + "-" + s._uiData.uiID, Log.IMPORTANT);
		if (s._callBack != null) {
			s._callBack.call(s._thisObject);
		}
	}

	/**模块结束，模块操作结束之后，结算之前
	 * @param func 主框架处理完成后的回调
	 * @param thisObj 回调的指向
	 * @param param 模块传入的附加参数
	*/
	public moduleEnd(func: Function = null, thisObj: any = null, param: any = null): void {
		let s = this;			
		s._callBack = func;
		s._thisObject = thisObj;
		Log.writeLog(MultiLang.str19 + "-" + s._uiData.uiID, Log.IMPORTANT);
		let curID: string = s._uiData.uiID;
		EgretProto.gc(curID);
		if (s._callBack != null) {
			s._callBack.call(s._thisObject);
		}
	}

	/**模块结算
	 * @param func 主框架处理完成后的回调
	 * @param thisObj 回调的指向
	 * @param param 模块传入的结算附加参数
	*/
	public moduleAccount(func: Function = null, thisObj: any = null, param: any = null): void {
		let s = this;
		s._callBack = func;
		s._thisObject = thisObj;
		if(s._uiData)Log.writeLog(MultiLang.str20 + "-" + s._uiData.uiID, Log.IMPORTANT);
		
		//统一调出结算
		if (s._callBack != null) {
			s._callBack.call(s._thisObject);
		}
	}

	/**模块退出，调用此方法前，确认模块的内存已经释放，如监听器都被移除了
	 * @param func 主框架处理完成后的回调
	 * @param thisObj 回调的指向
	 * @param param 模块传入的附加参数	 
	*/
	public moduleQuit(func: Function = null, thisObj: any = null, param: any = null): void {
		let s = this;		
		s._callBack = func;
		s._thisObject = thisObj;
		s._param = param;	
		s.doModuleQuit();
	}
	private doModuleQuit():void
	{let s = this;		
		Log.writeLog("doModuleQuit:" + s._uiData.uiID, Log.IMPORTANT);		
		s.moduleAccount(null,this);		
					
		if (s._callBack != null) {
			s._callBack.call(s._thisObject, s._param);
		}
	}
	
	private dependLoadProg(e:egret.Event):void
	{									
		let s = this;
		if(s._dependLoadProgCall!=null)
			s._dependLoadProgCall.call(s._dependLoadProgObj);		
	}

	private dependLoadComp(l: GYLite.LoadInfo): void {
		let s = this;				
		if (l.content == null) {			
			Log.writeLog(MultiLang.str3 + l.path, Log.WARN);
			return;
		}
		Log.loadLog(l);		
		Main.instance.myLoader.loadGYCompressBytes(l.content.res, s.resUncompressComp, s, null, null, {key:l.path});
	}	
	private resUncompressComp(l: GYLite.CompressLoadInfo = null): void {
		let s = this;
		let flag: boolean;
		if (l == null || l.resCount == 0) {							
			if(l)Log.uncompressLog(l,l.param.key);
			if (!s.loadNextLib())//没有下一个会返回false，结束流程//s._dependCounts == 0) 
			{
				let i: number, len: number;
				let res: GYLite.ResObject;
				len = s._depends.length;
				for (i = 0; i < len; ++i) {					
					res = GYLite.GYLoader.getDataRes(URLConf.moduleLibsJS.replace(/\*/g, s._depends[i]));
					//非小游戏平台中，非debug环境或libRelease标志为true则需要确保公共库代码已经注入
					if (egret.wxgame.wx == null && (!GameManager.debug || ModuleWatcher.libRelease)) {						
						if (res == null) {
							Log.writeLog(MultiLang.str16 + s._depends[i], Log.WARN);
							flag = true;
						}
						else
						{						
							Log.recordTime();
							UIControl.evalCodeMulti(res.res, "var " + s._depends[i].split(".")[0] + ";!")							
							Log.evalLog(s._depends[i]);
						}
							
					}
					if(res)
					{						
						GYLite.GYLoader.setDataRes(res.pathKey,null);//由于代码可能是大量的，所以解析完后里面清理，以免占用内存
					}
						
				}				
				if (flag)
					return;
				if(s._dependLoadProgCall!=null)
				{
					s._dependLoadProgCall.call(s._dependLoadProgObj);
					s._dependLoadProgCall = s._dependLoadProgObj = null;
				}
				EgretProto.curRunUIID = s._uiData.uiID;
				EgretProto.inject(s._uiData.uiID);//注入覆盖egret的一些方法
				if(s._haveFairygui)
					FairyGUIProto.inject();//注入覆盖fairygui的一些方法				
				s.preStartOn();//此处初始化模块，电脑约耗费100毫秒，看模块情况	
			}
			
		}
	}
	/**依赖库加载的百分比*/
	public get dependLoadedPercent(): number {
		let s = this;
		let max: number;
		if(s._dependCounts != s._dependCounts)return 1;
		max = s._dependCounts;
		let per:number,addPer:number;
		if(max == 0)return 1;
		addPer = (Date.now() - s._loadStartTime);				
		per = (1 - (s._libList.length+1) / max);
		addPer = 0.05*Math.log(per*addPer+1);//时效进度增益，做个假的进度效果		Math.log(10000)*0.05=0.57;
		per += addPer;		
		if(per > 1)per = 1;
		else if(per < 0)per = 0;
		return per;
	}
	public get depends(): Array<string> {
		return this._depends;
	}	
	
}